# coding:utf-8
# 王一舟
# ApiTestRunner.py
import copy

from tools.Dynamic_Title import dynamicTitle #动态生成标题/模块名/优先级/备注
# from tools.case_parser import case_parser

from extend.keywords import KeyWords
# import pathlib
# import pytest
import allure
from tools.varRender import refresh #字符串变量渲染方法 ≈TEMPLATE
from core.globalContext import g_Context #导入全局变量




'''
核心执行器
'''
#数据格式都维护成一样 -- 模板
#基于这个模板,需要进行执行 -- 核心执行器


'''因为在执行文件中使用了CasesPlugin()插件,所以下面的读取文件以及DDT部分可以不要了'''

class TestRunner():

    #
    # # #TODO 1:读取用例文件数据
    # case_path = pathlib.Path(__file__).parents[1].resolve() / 'excel_files'
    # caseInfo = case_parser(case_dir=case_path,case_type="excel") #{"case_infos": [],  "case_names": []}

    #TODO 2:
    #case_parser()返回的格式是: {"case_infos": [],  "case_names": []}
    #所以DDT的数据要从字典中再获取 caseInfo["case_infos"]


    # @pytest.mark.parametrize("caseinfo", caseInfo["case_infos"])
    def test_case_ex(self,caseInfo):

        print("\n当前用例的测试数据是:",caseInfo)
        # TODO 2-1:动态生成当前测试用例的标题 -- 弃用
        # allure.dynamic.title(caseInfo["_case_name"]) # 动态获取标题 , 被dynamicTitle取代

        # TODO 2-2:动态生成标题/模块名/优先级/备注
        dynamicTitle(caseInfo)#动态生成标题/模块名/优先级/备注

        #TODO 2-2:基于步骤一步步执行
        try:
            #实例化关键字对象
            K = KeyWords()

            #TODO 扩展 单文件DDT,如果用例中存在ddts,那么就说明用例数据中已经处理好ddt_context字段了,需要把context字段放到全局变量中,供step步骤做template渲染
            ddt_context = caseInfo.get("ddt_context",{})#获取当前用例中已经存在的ddt用的context,拿不到就给空字典

            #因为yaml中所有步骤数据(字典格式)都放在一个名为STEPS的列表中,所以要先遍历它
            steps = caseInfo.get("steps","测试步骤steps未获取成功")

            for step in steps:
                #获取每个步骤的 步骤名和步骤值
                step_name = list(step.keys())[0] #step_name是一个字符串文本
                step_value = list(step.values())[0] #step_value 是一个字典
                #注意dict.keys()/values()获取的是一个对象列表,要取值只能把它变成一个列表然后用下标取值
                print("\n开始执行步骤:",step_name,"--",step_value)

                #TODO 2-3: 每一个步骤都要进行变量的渲染,将步骤中存在的{{}}都渲染替换掉
                context = copy.deepcopy(g_Context().show_dict()) #深度copy全局变量中的所有数据
                context.update(ddt_context)  # 将ddt的参数更新到全局变量中
                step_value = refresh(target=step_value,context=context)#对所有步骤进行渲染,返回渲染完的参数数据

                #TODO 2-4:基于每个步骤的关键字,找到对应的方法,然后把参数传给它
                #通过[反射]的方式找到对应的方法
                with allure.step(step_name): #报告中生成每个步骤的名字
                    func_name = step_value["关键字"] #"关键字"对应的是,在keywords中具体的方法名
                    try: #判断一下是否能正常获取到关键字方法
                        key_func = K.__getattribute__(func_name) #通过keywords的实例化对象[反射]到对应的方法
                    except AttributeError as e: #属性错误
                        print("keywords中没有这个关键字的方法",e)

                    #TODO 2-5:调用方法 - 把参数的字典拆包传给映射的方法
                    key_func(**step_value)

        finally:
            print("当前步骤结束")


# if __name__ == '__main__':
#     print(pathlib.Path(__file__).parents[1].resolve() / 'yaml_files' / "03_加入购物车成功用例.yaml")